#include "TcpServer.hpp"
#include "Protocol.hpp"

using namespace NetWork;
using namespace Protocol;
using namespace std;

// Socket demo code
// int main(int argc, char* argv[])
// {
//     if(argc != 2)
//     {
//         cout << "Usage: " << argv[0] << " port" << endl;
//         return 1;
//     }

//     uint16_t port = atoi(argv[1]);

//     Socket* server = new TcpSocket();
//     server->BuildListenSocketMethod(port);

//     while(true)
//     {
//         string peerip;
//         uint16_t peerport;
//         Socket* new_socket = server->AcceptSocketOrDie(&peerip, &peerport);
//         cout << "Accept a connection from [" << peerip << ":" << peerport << "], client fd = " << new_socket->GetSockfd() << endl;
//     }

//     return 0;
// }

// Server code demo -- no protocol customization
// int main(int argc, char* argv[])
// {
//     if(argc != 2)
//     {
//         cout << "Usage: " << argv[0] << " port" << endl;
//         return 1;
//     }

//     uint16_t port = atoi(argv[1]);

//     auto handler_lambda = [](Socket* client_socket) -> std::string {
//         std::string data;
//         bool ret = client_socket->Recv(&data, 1024);
//         if(ret)
//         {
//             cout << "Recv data from client: " << data << endl;
//         }
//         //sleep(1);
//         return data;
//     };
//     auto handler_request = std::bind(handler_lambda, std::placeholders::_1);

//     TcpServer server(port, handler_request);
//     server.Loop();

//     return 0;
// }

// Server code demo -- with self protocol customization in "Protocol.hpp"
// int main(int argc, char* argv[])
// {
//     if(argc != 2)
//     {
//         cout << "Usage: " << argv[0] << " port" << endl;
//         return 1;
//     }

//     uint16_t port = atoi(argv[1]);

//     auto handler_lambda = [](Socket* client_socket) -> std::string {
//         std::string data;
//         bool ret = client_socket->Recv(&data, 1024);
//         if(ret)
//         {
//             std::string uncoded_data;
//             if(!PacketHandler::Decode(data, &uncoded_data))
//             {
//                 cout << "Decode data failed!  data = " << data << endl;
//                 return "";
//             }
//             cout << "Recv data from client: " << uncoded_data << endl;
//         }
//         return data;
//     };
//     auto handler_request = std::bind(handler_lambda, std::placeholders::_1);

//     TcpServer server(port, handler_request);
//     server.Loop();

//     return 0;
// }

// Use Protocol customization and Calculate operation
#include "Calculate.hpp"
using namespace CalculateNS;
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cout << "Usage: " << argv[0] << " port" << endl;
        return 1;
    }

    uint16_t port = atoi(argv[1]);

    auto handler_lambda = [](std::shared_ptr<Socket> client_socket) -> std::string
    {
        // 1. receive data from client
        std::string data;
        bool ret = client_socket->Recv(&data, 1024);
        if (ret)
        {
            // 1) decode data -- unpack
            std::string decoded_data;
            if (!PacketHandler::Decode(data, &decoded_data))
            {
                cout << "Decode data failed!  data = " << data << endl;
                return "";    // return empty string to indicate error
            }
            // 2) deserialize request by decoded data
            Factory factory;
            std::shared_ptr<Request> req = factory.CreateCalRequest();
            req->Deserialize(decoded_data);
            // 3) do calculate
            Calculate cal;
            std::shared_ptr<Response> resp = cal.Do(req);
            auto cal_resp = std::dynamic_pointer_cast<Cal_Response>(resp);
            // 4) get result and error code from response
            if (cal_resp->GetErrorCode() != 0)
            {
                cout << "Calculate error! error code = " << cal_resp->GetErrorCode() << endl;
                return "";
            }
            // 5) print log
            std::string req_serialized;
            req->Serialize(&req_serialized);
            cout << "[Calculate] " << req_serialized << " = " << cal_resp->GetResult() << endl;

            // 2. send response to client
            std::string resp_serilized;
            cal_resp->Serialize(&resp_serilized);
            std::string encoded_data = PacketHandler::Encode(resp_serilized);

            client_socket->Send(encoded_data);
        }
        return data;
    };
    auto handler_request = std::bind(handler_lambda, std::placeholders::_1);

    TcpServer server(port, handler_request);
    server.Loop();

    return 0;
}